# Digital to Analog
# TLC5620

# TLC5620           Pi
# CLK(7)    -----   Pin37
# DATA(6)   -----   Pin38
# LOAD(8)   -----   Pin40

# VDD(14)   -----   5V
# GND(1)    -----   GND
# LDAC(13)  -----   GND
# REFA(2)   -----   3.3V
# DACA(12)  -----   Analog Output

# 此文件用于控制 DAC_TLC5620 模块，将数字信号转换为模拟信号
import RPi.GPIO as GPIO

# 定义 DAC_TLC5620 引脚连接到树莓派的 GPIO 引脚
DAC_CLK=26 # 时钟信号引脚
DAC_DATA=20 # 数据输入引脚
DAC_LOAD=21 # 加载信号引脚

# 初始化 DAC_TLC5620 模块
# 参数 clk: 时钟信号引脚，默认为 26
# 参数 data: 数据输入引脚，默认为 20
# 参数 load: 加载信号引脚，默认为 21
def setup(clk=26,data=20,load=21): 
    global DAC_CLK,DAC_DATA,DAC_LOAD
    DAC_CLK=clk
    DAC_DATA=data
    DAC_LOAD=load
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(DAC_CLK,GPIO.OUT)  # 设置时钟信号引脚为输出模式
    GPIO.setup(DAC_DATA,GPIO.OUT)  # 设置数据输入引脚为输出模式
    GPIO.setup(DAC_LOAD,GPIO.OUT)  # 设置加载信号引脚为输出模式
    
# 清理 GPIO 引脚
def destroy():
    GPIO.cleanup()
    
# 向 DAC_TLC5620 发送一个数据
# 参数 num: 要发送的数据，范围 0 - 255
# 参数 a1: 通道选择位 1，默认为 0
# 参数 a0: 通道选择位 0，默认为 0
# 参数 rng: 范围选择位，默认为 0
def SendOneData(num,a1=0,a0=0,rng=0):
    # 将 LOAD 设为高电平
    GPIO.output(DAC_LOAD,1)
    
    # 给 DATA 端口依次输入 a1, a0, rng
    # a1 和 a0 用于选择通道，由于二者均为 0，故选的是 DACA
    GPIO.output(DAC_DATA,a1)
    GPIO.output(DAC_CLK,1)
    GPIO.output(DAC_CLK,0)   # 输出 A1
    
    GPIO.output(DAC_DATA,a0)
    GPIO.output(DAC_CLK,1)
    GPIO.output(DAC_CLK,0)   # 输出 A0
    
    GPIO.output(DAC_DATA,rng)
    GPIO.output(DAC_CLK,1)
    GPIO.output(DAC_CLK,0)   # 输出 RNG
    
    i=8
    while i>0: # 持续将数据左移获得最高位并输出
        num=num%256 # 获得数据低8位
        this_bit=int(num/128)    # 获得当前最高位
        GPIO.output(DAC_DATA,this_bit)
        GPIO.output(DAC_CLK,1)
        GPIO.output(DAC_CLK,0)   # 输出当前位数据
        num=num<<1 
        i=i-1

    # 将 LOAD 设为高电平，把数据锁存至串行数据寄存器中
    GPIO.output(DAC_LOAD,0)
    
# 循环等待用户输入一个 0 - 255 的整数并发送到 DAC_TLC5620
def loop():
    while 1:
        num=int(input("input a integer(0~255):")) # 测试，用户输入一个数字
        SendOneData(num)
        
if __name__ == '__main__':
    setup()
    try:
        loop()
    except KeyboardInterrupt:  # 当按下 Ctrl+C 时，执行清理操作
        destroy()
